// Self-shadowed relief mapping shader plus ambient occlusion mapping using the relief height map shader
// Have to be used with BumpMapping.frag

#define NUMBER_OF_SAMPLES (24+1);

uniform float fHeightScale;
uniform vec3 fvSamplingVectors[NUMBER_OF_SAMPLES];

vec2 fvGetCorrectSamplingPosition(vec2 texCoord, vec3 view)
{
   const int numStepsLinear = 16;
   const int numStepsBinary = 10;
   
   vec3 position = vec3( texCoord, 0.0 );
   
   view.xy *= view.z;
   view.xy *= fHeightScale;
   
   int i;
   for (i = 0; i < numStepsLinear; ++i)
   {
      vec4 tex = texture2D( bumpMap, position.xy );
      if ( position.z < tex.w ) position += view;      
      else i = numStepsLinear;
   }
   
   for (i = 0; i < numStepsBinary; ++i)
   {
      view *= 0.5;
      vec4 tex = texture2D( bumpMap, position.xy );
      if ( position.z < tex.w ) position += view;
      else position -= view;
   }
   
   return position.xy;
}

bool bIsSelfShadowed(vec2 texCoord, vec3 light)
{
   const int numShadowSteps = 16;
   float stepf = 1.0 / float(numShadowSteps);
   vec2 delta = vec2(light.x, -light.y) * fHeightScale / vec2(float(numShadowSteps) * light.z);
   vec4 tex = texture2D( bumpMap, texCoord );
   float height = tex.w + stepf * 0.1;
   vec2 offsetCoord = texCoord;
   
   while ( (tex.w < height) && (height < 1.0) ) {
      height += stepf;
      offsetCoord += delta;
      tex = texture2D( bumpMap, offsetCoord );
   }
   
   return (tex.w < height);
}

float fvGetAmbientOcclusionFactor(vec2 texCoord)
{
   float fInvAmbientOcclusionFactor = 0.0;
   
   for (int i = 0; i < NUMBER_OF_SAMPLES; ++i)
      if ( !bIsSelfShadowed( texCoord, normalize( fvSamplingVectors[i] ) ) )
         fInvAmbientOcclusionFactor += (1.0 / float(NUMBER_OF_SAMPLES));
   
   return 1.0 - fInvAmbientOcclusionFactor;
}
